package com.chandon.juc.thread_communication.AddStringsToList;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.LockSupport;

/**
 * A与B线程，A线程向一个集合里面依次添加元素"abc"字符串，一共添加十次
 * 当添加到第五次的时候，希望B线程能够收到A线程的通知，然后B线程执行相关的业务操作。
 *
 * @author Dong
 */
@Slf4j
public class UseLockSupport {

	/**
	 * ArrayList是线程不安全的，当元素添加进去以后，还未进行更新size，就会出现问题。
	 * 可以使用线程安全的容器，如：
	 * Collections.synchronizedList(new ArrayList<>(10));
	 * 或将add方法与size方法封装成线程安全的。
	 * <p>
	 * 疑问：volatitle修饰的list是引用，没有修饰到内部的值size，为何起作用了。
	 * 猜测：被volatile关键字修饰的对象作为类变量或实例变量时，其对象中携带的类变量和实例变量也相当于被volatile关键字修饰了
	 */
	public static volatile List<String> list = new ArrayList<>(10);

	/**
	 * locksupport
	 */

	static Thread t1, t2;

	public static void useLockSupport() {

		t1 = new Thread(() -> {


			for (int i = 0; i < 10; i++) {
				list.add("abc");
				System.out.println("list.size:" + list.size());
				if (list.size() == 4) {

					LockSupport.unpark(t2);
					System.out.println("线程B要开始执行了");
					// 严格来说==4时让t2执行，而不是>4的时候执行，所以park一下，可以将t1提升全局变量，在t2中unpark
					LockSupport.park();


				}
			}
		});


		t2 = new Thread(() -> {

			// 可以省略这个判断，因为t1中只在满足条件时unpark t2
			if (list.size() != 4) {
				LockSupport.park();
				LockSupport.unpark(t1);

			}

			System.out.println("线程B开始执行,size:" + list.size());

		});


		t1.start();
		t2.start();


	}


}

